<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="uc1lr" id="uc1lr"><span data-lake-id="u7dbb73ea" id="u7dbb73ea">典型回答</span></h1>
  <p data-lake-id="u468fae24" id="u468fae24"><br></p>
  <p data-lake-id="ubdeb443a" id="ubdeb443a"><span data-lake-id="u916e9667" id="u916e9667">FactoryBean和BeanFactory是Spring中的两个重要的概念。先看一下他们的类定义：</span></p>
  <p data-lake-id="u398243b8" id="u398243b8"><span data-lake-id="u14cb8813" id="u14cb8813">​</span><br></p>
  <p data-lake-id="uf7b79eaa" id="uf7b79eaa"><span data-lake-id="ud758edd5" id="ud758edd5">FactoryBean：</span></p>
  <pre lang="java"><code>
package org.springframework.beans.factory;

public interface FactoryBean&lt;T&gt; {

  T getObject() throws Exception;
  
  Class&lt;?&gt; getObjectType();
  
  boolean isSingleton();
}
</code></pre>
  <p data-lake-id="u4b8c79ad" id="u4b8c79ad"><br></p>
  <p data-lake-id="u807d114f" id="u807d114f"><span data-lake-id="udb692f8d" id="udb692f8d">BeanFactory：</span></p>
  <pre lang="java"><code>
package org.springframework.beans.factory;

public interface BeanFactory {
	Object getBean(String name) throws BeansException;

  &lt;T&gt; T getBean(String name, Class&lt;T&gt; requiredType) throws BeansException;

  Object getBean(String name, Object... args) throws BeansException;

  &lt;T&gt; T getBean(Class&lt;T&gt; requiredType) throws BeansException;

  &lt;T&gt; T getBean(Class&lt;T&gt; requiredType, Object... args) throws BeansException;

  boolean containsBean(String name);

  boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

  boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

  // ...
}
</code></pre>
  <p data-lake-id="u153ff22f" id="u153ff22f"><br></p>
  <p data-lake-id="u47136ba7" id="u47136ba7"><span data-lake-id="ua82f7fe5" id="ua82f7fe5">至少从代码上来看，这两个东西</span><strong><span data-lake-id="ua55b4765" id="ua55b4765">都是接口（interface)</span></strong><span data-lake-id="uc503424d" id="uc503424d">，然后</span><strong><span data-lake-id="u32043bec" id="u32043bec">都是在org.springframework.beans.factory包</span></strong><span data-lake-id="uf839162f" id="uf839162f">下面的。</span></p>
  <p data-lake-id="ue20adf93" id="ue20adf93"><span data-lake-id="u22563b48" id="u22563b48">​</span><br></p>
  <p data-lake-id="ue4959619" id="ue4959619"><span data-lake-id="u229e81c9" id="u229e81c9">网上有很多概念的解释，说明他俩的区别，但是很多人还是看不懂，下面是的解释我</span><u><span data-lake-id="u701f62b4" id="u701f62b4">结合了具体的case</span></u><span data-lake-id="uc8ccc6da" id="uc8ccc6da">，帮助大家更好地理解他们的作用，理解了各自的作用，那么区别自然也就理解了。</span></p>
  <p data-lake-id="u1a77f75f" id="u1a77f75f"><span data-lake-id="u0ca12ca8" id="u0ca12ca8">​</span><br></p>
  <h3 data-lake-id="tTg7F" id="tTg7F"><span data-lake-id="ua41395b1" id="ua41395b1">BeanFactory</span></h3>
  <p data-lake-id="uc0dfe47a" id="uc0dfe47a"><span data-lake-id="u163ebb42" id="u163ebb42">​</span><br></p>
  <p data-lake-id="uac247b4c" id="uac247b4c"><span data-lake-id="u8837f128" id="u8837f128">BeanFactory比较常用，名字也比较容易理解，就</span><strong><span data-lake-id="uaae66a34" id="uaae66a34">是Bean工厂，他是整个Spring IoC容器的一部分，负责管理Bean的创建和生命周期。</span></strong></p>
  <p data-lake-id="u635aae2f" id="u635aae2f"><span data-lake-id="ubfc87d59" id="ubfc87d59">​</span><br></p>
  <p data-lake-id="u6ab3bf13" id="u6ab3bf13"><span data-lake-id="u7c4bdf67" id="u7c4bdf67">其中提供了一系列方法，可以让我们获取到具体的Bean实例。你可能没有直接用过BeanFactory，但是你肯定用过或者见过：</span></p>
  <p data-lake-id="ub8ecc574" id="ub8ecc574"><span data-lake-id="u82104a57" id="u82104a57">​</span><br></p>
  <pre lang="java"><code>
applicationContext.getBean(requiredType);

applicationContext.getBean(name);
</code></pre>
  <p data-lake-id="u1b510f7d" id="u1b510f7d"><br></p>
  <p data-lake-id="u5c66e6b2" id="u5c66e6b2"><span data-lake-id="u75498bd8" id="u75498bd8">以上就是我们经常用的，在Spring的上下文中通过bean名称或者类型获取bean的方式，而这里的ApplicationContext，其实就是一种BeanFactory。这里面调用的getBean方法，就是上面我们在BeanFactory中看到的方法。</span></p>
  <p data-lake-id="uf0fb3852" id="uf0fb3852"><span data-lake-id="u46eb4b29" id="u46eb4b29"></span></p>
  <p data-lake-id="ub5e17ed4" id="ub5e17ed4"><span data-lake-id="u0d2bae0b" id="u0d2bae0b">所以，</span><strong><span data-lake-id="u8481346b" id="u8481346b">BeanFactory是Spring IoC容器的一个接口，用来获取Bean以及管理Bean的依赖注入和生命周期。</span></strong></p>
  <p data-lake-id="u707d675c" id="u707d675c"><span data-lake-id="u68044ac1" id="u68044ac1">​</span><br></p>
  <h3 data-lake-id="VhXXM" id="VhXXM"><span data-lake-id="uc22d31ce" id="uc22d31ce">FactoryBean</span></h3>
  <p data-lake-id="u4aa8370f" id="u4aa8370f"><br></p>
  <p data-lake-id="uf2947740" id="uf2947740"><strong><span data-lake-id="u1db3f292" id="u1db3f292">FactoryBean是一个接口，用于定义一个工厂Bean，它可以产生某种类型的对象。</span></strong><span data-lake-id="u129f5842" id="u129f5842">当在Spring配置文件中定义一个Bean时，如果这个Bean实现了FactoryBean接口，那么Spring容器不直接返回这个Bean实例，而是返回FactoryBean#getObject()方法所返回的对象。</span></p>
  <p data-lake-id="u3b4b52c5" id="u3b4b52c5"><span data-lake-id="uc7e2068c" id="uc7e2068c">​</span><br></p>
  <p data-lake-id="u5e7abbb3" id="u5e7abbb3">
   <del><span data-lake-id="ufe77cc69" id="ufe77cc69">是不是还是听不懂？</span></del></p>
  <p data-lake-id="u9e821d75" id="u9e821d75"><span data-lake-id="u6efbf2ed" id="u6efbf2ed">​</span><br></p>
  <p data-lake-id="uab53a83e" id="uab53a83e"><span data-lake-id="u8d9f09cc" id="u8d9f09cc">那我给你举个具体的例子你就知道了。</span></p>
  <p data-lake-id="u12205d90" id="u12205d90"><span data-lake-id="u60e85d22" id="u60e85d22">​</span><br></p>
  <p data-lake-id="u325824cb" id="u325824cb"><span data-lake-id="uafadddeb" id="uafadddeb">Dubbo用过吧（</span><u><span data-lake-id="u8a247041" id="u8a247041">没用过？那可能理解起来比较吃力，因为FactoryBean确实是在很多框架中用到的比较多，比如Kafka、dubbo等各种框架中都会用他来和Spring做集成</span></u><span data-lake-id="ueaa4c626" id="ueaa4c626">）。</span></p>
  <p data-lake-id="u11177dc1" id="u11177dc1"><span data-lake-id="uee8d01f4" id="uee8d01f4">​</span><br></p>
  <p data-lake-id="u1116cbe0" id="u1116cbe0"><span data-lake-id="uf5aec784" id="uf5aec784">当我们想要在Dubbo中定义一个远程的提供者提供的的Bean的时候，可以用@DubboReference或者&lt;dubbo:reference&gt; </span></p>
  <p data-lake-id="u4a449c8b" id="u4a449c8b"><span data-lake-id="u06867359" id="u06867359" class="lake-fontsize-12" style="color: rgb(55, 65, 81)">​</span><br></p>
  <p data-lake-id="ub4374766" id="ub4374766"><span data-lake-id="ud7e36712" id="ud7e36712" class="lake-fontsize-12" style="color: rgb(55, 65, 81)">而</span><strong><span data-lake-id="u0edb2509" id="u0edb2509" class="lake-fontsize-12" style="color: rgb(55, 65, 81)">这两种定义方式的最终实现都是一个Dubbo中的</span></strong><strong><span data-lake-id="udab743b0" id="udab743b0" style="color: var(--tw-prose-code)">ReferenceBean</span></strong><strong><span data-lake-id="u43fafe57" id="u43fafe57" class="lake-fontsize-12" style="color: rgb(55, 65, 81)"> ，它负责创建并管理远程服务代理对象。而这个</span></strong><strong><span data-lake-id="ue7155d92" id="ue7155d92" style="color: var(--cyanosis-title-color)">ReferenceBean就是一个FactoryBean的实现。</span></strong></p>
  <p data-lake-id="udab9c8c7" id="udab9c8c7"><span data-lake-id="u511f3019" id="u511f3019" style="color: var(--cyanosis-title-color)">​</span><br></p>
  <pre lang="java"><code>
public class ReferenceBean&lt;T&gt; implements FactoryBean&lt;T&gt;,
        ApplicationContextAware, BeanClassLoaderAware, BeanNameAware, InitializingBean, DisposableBean {

}
</code></pre>
  <p data-lake-id="u895a735f" id="u895a735f"><strong><span data-lake-id="u32d7d011" id="u32d7d011" class="lake-fontsize-12" style="color: var(--tw-prose-code)">​</span></strong><br></p>
  <blockquote data-lake-id="u196ac7a3" id="u196ac7a3">
   <p data-lake-id="u6d40a9d0" id="u6d40a9d0"><span data-lake-id="uef14947f" id="uef14947f">ReferenceBean的主要作用是创建并配置Dubbo服务的代理对象。这些代理对象允许客户端像调用本地方法一样调用远程服务。创建Dubbo服务代理通常涉及复杂的配置和初始化过程，包括网络通信设置、序列化配置等。通过ReferenceBean将这些复杂性封装起来，对于使用者来说，只需要通过简单的Spring配置即可使用服务。</span></p>
  </blockquote>
  <p data-lake-id="u5add41ee" id="u5add41ee"><span data-lake-id="ubff5fc7d" id="ubff5fc7d">​</span><br></p>
  <p data-lake-id="u8ca3e0db" id="u8ca3e0db"><span data-lake-id="u5b7dd75b" id="u5b7dd75b">ReferenceBean 实现了 FactoryBean 接口并实现了getObject方法。在getObject()方法中，ReferenceBean会给要调用的服务创建一个动态代理对象。这个代理对象负责与远程服务进行通信，封装了网络调用的细节，使得远程方法调用对于开发者来说是透明的。</span></p>
  <p data-lake-id="u9f7fd94e" id="u9f7fd94e"><span data-lake-id="u4451b775" id="u4451b775">​</span><br></p>
  <p data-lake-id="u7b5aaf25" id="u7b5aaf25"><span data-lake-id="u9fbe0c89" id="u9fbe0c89">通过 FactoryBean 实现，ReferenceBean 还可以延迟创建代理对象直到真正需要时，这样可以提升启动速度并减少资源消耗。此外，它还可以实现更复杂的加载策略和优化。</span></p>
  <p data-lake-id="ue2b4890e" id="ue2b4890e"><span data-lake-id="u3948aac2" id="u3948aac2">​</span><br></p>
  <p data-lake-id="u2842b743" id="u2842b743"><span data-lake-id="u01137986" id="u01137986">通过实现 FactoryBean，ReferenceBean 能够很好地与Spring框架集成。这意味着它可以利用Spring的依赖注入，生命周期管理等特性，并且能够被Spring容器所管理。</span></p>
  <p data-lake-id="u0c29e1ea" id="u0c29e1ea"><span data-lake-id="ua4c3dd0e" id="ua4c3dd0e">​</span><br></p>
  <p data-lake-id="ub1d5247c" id="ub1d5247c"><span data-lake-id="u2e44435b" id="u2e44435b">所以，</span><strong><span data-lake-id="u3c1b6c85" id="u3c1b6c85">FactoryBean通常用于创建很复杂的对象，比如需要通过某种特定的创建过程才能得到的对象。例如，创建与JNDI资源的连接或与代理对象的创建。就如我们的Dubbo中的ReferenceBean。</span></strong></p>
  <p data-lake-id="ud61b0e03" id="ud61b0e03"><br></p>
  <h1 data-lake-id="bhcPb" id="bhcPb"><span data-lake-id="u475a02c2" id="u475a02c2">扩展知识</span></h1>
  <p data-lake-id="u55428543" id="u55428543"><br></p>
  <h2 data-lake-id="rZSmK" id="rZSmK"><span data-lake-id="u397d9f2d" id="u397d9f2d">ApplicationContext使用</span></h2>
  <p data-lake-id="ue1966ace" id="ue1966ace"><br></p>
  <p data-lake-id="u2d4a9fd9" id="u2d4a9fd9"><span data-lake-id="u73898693" id="u73898693">我们知道，ApplicationContext作为BeanFactory的具体实现，他可以在Spring的的上下文中获取Bean，那么什么时候可以用到它呢？</span></p>
  <p data-lake-id="u0a956402" id="u0a956402"><span data-lake-id="uc89e879a" id="uc89e879a">​</span><br></p>
  <p data-lake-id="u9b304f0e" id="u9b304f0e"><span data-lake-id="ud194265f" id="ud194265f">一般来说，我们的Bean都是有Spring自动注入的，不太需要我们自己从上下文中获取，但是想让Spring帮忙注入，有一个前提，那就是必须被注入的Bean和注入的Bean都交给Spring托管，简单点说就是要有@Service和@Autowire一起用。</span></p>
  <p data-lake-id="uec273b8e" id="uec273b8e"><span data-lake-id="uc570a8fd" id="uc570a8fd">​</span><br></p>
  <pre lang="java"><code>
@Service
public class HollisTestService{

	@Autowired
  private HollisTestRepo hollisTestRepo;

}
</code></pre>
  <p data-lake-id="u00b3488e" id="u00b3488e"><span data-lake-id="uc53c129d" id="uc53c129d"></span></p>
  <p data-lake-id="uec891574" id="uec891574"><span data-lake-id="uff9fd484" id="uff9fd484">这样才能把HollisTestRepo注入到HollisTestService中，但是有的时候，我们的HollisTestService如果不是Spring托管的呢，比如是自己new的，那就不行了。</span></p>
  <p data-lake-id="ude80e71b" id="ude80e71b"><span data-lake-id="uf15eec17" id="uf15eec17">​</span><br></p>
  <p data-lake-id="u7a6e379e" id="u7a6e379e"><span data-lake-id="u8fbd8f38" id="u8fbd8f38">比较典型的是当有的时候我们使用充血模型，需要在里面去查询或者操作数据库的时候，就需要在这个模型中获取到对应的bean。那么就需要ApplicationContext了。</span></p>
  <p data-lake-id="u02e5b35d" id="u02e5b35d"><span data-lake-id="uef8b411a" id="uef8b411a">​</span><br></p>
  <pre lang="java"><code>
public class CaseModel {
	 CollectionCaseItemService collectionCaseItemService = SpringContextHolder.getBean(CollectionCaseItemService.class);
}
</code></pre>
  <p data-lake-id="u0033cb92" id="u0033cb92"><br></p>
  <p data-lake-id="ubec54c3a" id="ubec54c3a"><span data-lake-id="u64d28052" id="u64d28052">这里面SpringContextHolder的实现如下：</span></p>
  <p data-lake-id="u380a3d1d" id="u380a3d1d"><span data-lake-id="udc95b1b0" id="udc95b1b0">​</span><br></p>
  <pre lang="java"><code>
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * Spring上下文工具
 *
 * @author Hollis
 */
@Component
public class SpringContextHolder implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }

    /**
     * 根据bean的名字获取Bean
     *
     * @param name
     * @return
     * @throws BeansException
     */
    public static Object getBean(String name) throws BeansException {
        return applicationContext.getBean(name);
    }

    /**
     * 根据bean的类型获取Bean
     *
     * @param requiredType
     * @param &lt;T&gt;
     * @return
     * @throws BeansException
     */
    public static &lt;T&gt; T getBean(Class&lt;T&gt; requiredType) throws BeansException {
        return applicationContext.getBean(requiredType);
    }
}

</code></pre>
  <p data-lake-id="u8e62b90a" id="u8e62b90a"><br></p>
 </body>
</html>